home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / Module source / zCasemod.txt / zCasemod.txt
Encoding:
Text File  |  1999-02-03  |  12.1 KB  |  475 lines  |  [TEXT/MSET]

  1. \ This module handles the implementation of our case constructs
  2. \ CASE[ and SELECT[.
  3. \ Notice that we don't use any assembler at all, and only need one
  4. \ special handler word CaseJMP to compile an indexed dispatch for SELECT[.
  5. \ We compile sequences that the optimizer will pick up so that the resulting
  6. \ code is pretty well optimum anyway.  The key to this is the use of the
  7. \ pseudo-value "Treg" which is actually the machine register D1.
  8.  
  9.  
  10. false    constant    case_dbg?
  11. \ : do_case_dbg  true -> case_dbg?  ;
  12.  
  13.  
  14.  
  15. enum{  keyed_case  indexed_case  }
  16.  
  17. 240    constant    KEYED_CHK
  18. 250    constant    INDEXED_CHK
  19.  
  20. (*
  21. : compBR
  22.     1 operands
  23.     adjust_stks
  24.     opnd1 ( invert?) true  setup_conditional_branch
  25.     free: opnd1
  26.     reg: opnd1 NIF  false -> using_CR0  THEN
  27.     compile: branch_instrn
  28. ;
  29. *)
  30.  
  31. : compUBR    compile_unconditional_branch  ;
  32.  
  33.  
  34. : CASE[        \ ( -- saved-cstk CDP Schain Fchain endChain end_stub_cnt end-stub? chk )
  35.             \  Implements CASE[ .
  36.             
  37.     case_type                \ save over nested cases
  38.     keyed_case -> case_type
  39.     
  40.     2 -1  simple_equalize
  41.             \ we have to do this here in all cases, since [ below would
  42.             \ do it anyway, but we need to have the right cstk saved
  43.             \ first.  Actually we could probably do without saving and
  44.             \ restoring cstk, but it's best to keep the code as much
  45.             \ like the 68k version  as possible.
  46.     
  47.     save: cstk  save: fcstk        \ save cstk/fcstk state - this will apply at the start of
  48.                                 \  each stub
  49.     CDP -> backstop_CDP
  50.     CDP                    \ CDP for the start of the first stub
  51. \    eval" -> treg"
  52.     0                    \ initial success chain
  53.     0                    \ initial fail chain
  54.     0                    \ initial end chain
  55.     -1                    \ end_stub_cnt = undefined - no stubs yet
  56.     false                \ no end of stub yet
  57.     keyed_chk            \ check value
  58.     postpone [  ;        immediate
  59.  
  60.  
  61. : ADD_ENTRY  ( saved-cstk ) { chk link \ mark-addr -- link' }
  62.     restore: fcstk2  restore: cstk2            \ get rid of saved cstk/fcstk which we never need
  63.     pop: control_stk  -> mark-addr    \ mark addr is addr of branch instrn
  64.     link IF
  65.         link  mark-addr 2+ wdispl!    \ store prev mark (if any) in lo 2 bytes of br
  66.     THEN
  67.     mark-addr                          \ mark addr is new link
  68. ;
  69.  
  70. : RESOLVE  { link \ nxt -- }
  71.     BEGIN
  72.         link
  73.     WHILE
  74. \ need these next two lines while we're debugging - and aren't we always...
  75.         link 2+ w@x -800 0 within?
  76.         NIF
  77.             db  cr ." garbage link in resolve" 1 die THEN  drop
  78.  
  79.         link 2+ wdisplace -> nxt
  80.         link push: control_stk  0 push: control_flags  120  >resolve
  81.         nxt -> link
  82.     REPEAT  ;
  83.  
  84.  
  85. \ FIX_STUB is called at the end of a stub.  We do many strange and
  86. \ intricate things...
  87.  
  88. : FIX_STUB  { stub_start_CDP Schain Fchain endChain end_stub_cnt
  89.             -- endChain' end_stub_cnt' }
  90. case_dbg? if db cdp drop then
  91.  
  92.     end_stub_cnt 0< IF  size: cstk  -> end_stub_cnt  THEN
  93.  
  94.     stub_start_CDP 4- -> startCDP  make_altered_regs_unknown
  95.     end_stub_cnt -1  simple_equalize
  96.  
  97.     compUBR  >mark                \ compile branch to end
  98.     endChain  add_entry            \ leaves updated endChain
  99.     Fchain resolve                \ resolves fail chain to here
  100.     end_stub_cnt
  101. ;
  102.  
  103.  
  104. : NEW_STUB  ( <saved-cstk> ) {    stub_start_CDP Schain Fchain endChain
  105.                                 end_stub_cnt end-stub? chk
  106.                                 lo hi  flg
  107.                              -- <saved-cstk> stub_start_CDP' Schain' Fchain' endChain' end-stub? chk }
  108. case_dbg? if db -999 cdp 2drop then
  109.     postpone ]                    \ Must be compiling for evaluates below
  110.     keyed_chk chk ?pairs
  111.     
  112.     end-stub?
  113.     IF    stub_start_CDP Schain Fchain endChain end_stub_cnt  fix_stub
  114.         -> end_stub_cnt  -> endChain
  115.         0 -> Schain  0 -> Fchain
  116.     THEN
  117.     
  118.     restore: fcstk  restore: cstk
  119.     save: cstk  save: fcstk     \ get cstk/fcstk to what they were at the start
  120.     update_refcnts                \  of the construct, which of course is
  121.                                 \  what it's got to be at the start of each
  122.                                 \  stub, just before the test.
  123.     hi lo <>
  124.     IF
  125.         lo  postpone literal
  126.         " over > nif"  evaluate
  127.         Fchain add_entry -> Fchain
  128.         hi  postpone literal
  129.         " over <" evaluate
  130.         flg
  131.         IF  postpone nif
  132.             Fchain add_entry -> Fchain
  133.         ELSE
  134.             postpone if
  135.             Schain add_entry -> Schain
  136.         THEN
  137.     ELSE
  138.         hi postpone literal
  139.         " over =" evaluate
  140.         flg
  141.         IF                \ starting a stub
  142.             postpone if
  143.             Fchain add_entry -> Fchain
  144.         ELSE            \ ], or whatever - not up to the stub yet
  145.             postpone nif
  146.             Schain add_entry -> Schain
  147.         THEN
  148.     THEN
  149.  
  150.     flg IF                \ we're starting the stub code right here
  151. case_dbg? if db 999 cdp 2drop then
  152.         CDP -> backstop_CDP            \ dispatch code gets mangled if we don't
  153.                                     \  do this!
  154.         Schain resolve
  155.         postpone drop                \ get rid of the test value
  156.         Schain IF  CDP 4-  -> Fchain  THEN
  157.                                     \ we clear Schain next time around,
  158.                                     \  since at FIX_STUB we need to know
  159.                                     \  whether anything was on it
  160.     ELSE
  161.         hi lo <>
  162.         IF
  163.             Fchain resolve  0 -> Fchain
  164.         THEN
  165.     THEN
  166.     CDP Schain Fchain endChain
  167.     end_stub_cnt
  168.     flg                                \ flg is end_stub? for next time
  169.     keyed_chk                        \ check value
  170. ;
  171.  
  172.  
  173. : DEFAULT  ( <saved-cstk> )  {    stub_start_CDP Schain Fchain endChain
  174.                                 end_stub_cnt end-stub? chk
  175.                              -- CDP end_stub_cnt endChain chk }
  176. case_dbg? if db $ 100 cdp 2drop then
  177.  
  178.     keyed_chk chk ?pairs
  179.  
  180.     end-stub?
  181.     IF    stub_start_CDP Schain Fchain endChain end_stub_cnt  fix_stub
  182.         -> end_stub_cnt  -> endChain
  183.     THEN
  184.     
  185.     restore: fcstk  restore: cstk    \ get cstk/fcstk to what they were at the start of
  186.     update_refcnts                    \  the construct, as we do for all the stubs
  187.     CDP -> backstop_CDP
  188.     
  189. \    postpone treg
  190. \    diff postpone literal  postpone +
  191.     CDP end_stub_cnt endChain  keyed_chk 1+
  192. ;
  193.     
  194.  
  195. : ]CASE  { dflt_CDP end_stub_cnt endChain chk -- }
  196.  
  197.     keyed_chk 1+ chk ?pairs
  198.  
  199.     dflt_CDP 4- -> startCDP  make_altered_regs_unknown
  200.     end_stub_cnt -1 simple_equalize        \ wind up default stub properly
  201.     
  202. \ now we'll resolve the endChain - note that the cstk state is already
  203. \  equalized to end_stub_cnt, which is precisely correct for here, so
  204. \  we can leave it alone.
  205.  
  206.     endChain resolve
  207.     -> case_type  ;            immediate
  208.  
  209.  
  210.  
  211. \ Now for an indexed case, with similar style syntax:
  212.  
  213.    0    value        MAXINDEX
  214.    0    value        MININDEX
  215.    
  216.    0    value        ADDRX        \ just for testing
  217.  
  218.  
  219. : SELECT[        \ ( -- lots )
  220.     case_type  maxindex  minindex    \ Save on stack for nested cases
  221.     indexed_case  -> case_type
  222.  
  223.     2 -1 simple_equalize
  224.             \ we have to do this here in all cases, since [ below would
  225.             \ do it anyway, but we need to have the right cstk saved
  226.             \ by >mark below.  Actually we could probably do without saving
  227.             \ and restoring cstk, but it's best to keep the code as much
  228.             \ like the 68k version  as possible.
  229.             
  230. \ 1 stk: cstk  gpr: cstk  select: GPRs  CDP put: ivar> lastrefcdp in GPRs
  231. \ printall: cstk  print: GPRs
  232.  
  233.     0 -> maxindex
  234.     big# -> minindex
  235.     $ dddddddd 1            \ Dummy 2-cell entry, so ]SELECT knows when to stop
  236.     compUBR >mark            \ Forward branch to dispatch code - also saves cstk state,
  237.                             \  which will apply at the start of each stub
  238.     drop                    \ drop >mark check value
  239.     CDP -> backstop_CDP
  240.     CDP                        \ CDP for the start of the first stub
  241.     0                        \ initial end chain
  242.     -1                        \ end_stub_cnt = undefined - no stubs yet
  243.     false                    \ no end of stub yet
  244.     indexed_chk                \ check value
  245.     postpone [  ;        immediate
  246.  
  247.  
  248.  
  249. : TBL_FIX_STUB  { stub_start_CDP endChain end_stub_cnt -- endChain' end_stub_cnt' }
  250.  
  251.     end_stub_cnt 0< IF  size: cstk  -> end_stub_cnt  THEN
  252.     
  253. \    stub_start_CDP 4- -> startCDP  make_altered_regs_unknown
  254.     0 -> startCDP  make_altered_regs_unknown
  255.  
  256.     end_stub_cnt -1 simple_equalize
  257.     compUBR >mark  endChain add_entry        \ leaves new endChain
  258.     end_stub_cnt
  259. ;
  260.     
  261.  
  262. : TBL_NEW_STUB  ( <saved-cstk> ) {    stub_start_CDP endChain
  263.                                     end_stub_cnt end-stub? chk index flg
  264.                                  -- index CDP <saved-cstk> CDP endChain' end_stub_cnt' end-stub? chk }
  265.  
  266.     postpone ]
  267.  
  268.     chk indexed_chk ?pairs
  269.  
  270.     index 0<  ?error 68
  271.  
  272. case_dbg? if db $ 102 cdp 2drop then
  273.  
  274.     index maxindex max  -> maxindex
  275.     index minindex min  -> minindex
  276.     maxindex 400 > if  msg# 69  then
  277.  
  278.     end-stub?
  279.     IF    stub_start_CDP endChain end_stub_cnt  tbl_fix_stub
  280.         -> end_stub_cnt  -> endChain
  281.     THEN
  282.  
  283.     CDP -> backstop_CDP            \ dispatch code gets mangled if we don't
  284.                                 \  do this!
  285.  
  286.     restore: fcstk  restore: cstk    \ get cstk/fcstk to what they were at the
  287.     update_refcnts                \  start of the construct, which of course is
  288.                                 \  what it's got to be at the start of each
  289.                                 \  stub.
  290.     index CDP                    \ leave these on the stack for the end
  291.     save: cstk  save: fcstk        \ save cstk/fcstk again for next stub
  292.     postpone drop                \ non-default stubs have index value dropped
  293.     CDP
  294.     endChain end_stub_cnt
  295.     flg                            \ flg is end_stub? for next time
  296.     indexed_chk                    \ check value
  297. ;
  298.  
  299.  
  300. : TBL_DEFAULT ( <saved-cstk> )  {    stub_start_CDP endChain
  301.                                     end_stub_cnt end-stub? chk
  302.                                  -- <saved-cstk> CDP endChain end_stub_cnt chk }
  303.     end-stub?
  304.     IF    stub_start_CDP endChain end_stub_cnt  tbl_fix_stub
  305.         -> end_stub_cnt  -> endChain
  306.     THEN
  307.  
  308.     restore: fcstk  restore: cstk    \ get cstk/fcstk to what they were at the start of
  309.     update_refcnts                    \  the construct, as we do for all the stubs
  310.     CDP -> backstop_CDP
  311.     
  312.     save: cstk  save: fcstk        \ save again for dispatch code
  313.     CDP                    \ here's where the default code will start
  314.     endChain end_stub_cnt  indexed_chk 1+
  315. ;
  316.  
  317.  
  318. : ]SELECT  ( $dddddddd 1 index CDP1 index CDP2 ... <saved-cstk> )
  319.         { dflt_CDP endChain end_stub_cnt chk \ tbl_start svCDP -- }
  320.  
  321.     indexed_chk 1+ chk ?pairs
  322.  
  323.     dflt_CDP endChain end_stub_cnt  tbl_fix_stub    \ wind up default stub properly
  324.     -> end_stub_cnt  -> endChain
  325.  
  326.     save: cstk  save: fcstk
  327.     restore: fcstk_temp  restore: cstk_temp        \ save cstk state for stub ends
  328.     
  329.     restore: fcstk  restore: cstk        \ get cstk/fcstk to what they were at the start
  330.     update_refcnts                        \  of the construct, which is what applies at the 
  331.                                         \  start of the dispatch code:
  332.  
  333.  \ Now we build the table:
  334.  
  335.      CDP -> tbl_start
  336.     maxindex minindex - 1+ 2* code_allot
  337.     dflt_CDP tbl_start -  ( now relative to tbl_addr )
  338.     CDP 2-                    \ last entry addr
  339.     tbl_start
  340.     DO  ( fill table with dflt addr initially )
  341.         dup  i w!
  342.     2 +LOOP
  343.     drop
  344.     BEGIN    ( index addr )    dup 1 =
  345.     NWHILE
  346.         ( index addr )  tbl_start -  swap minindex - 2* tbl_start + w!
  347.     REPEAT
  348.     2drop
  349.     
  350. \ Now we generate the dispatch code:
  351.  
  352.     code_align
  353.     120                    \ check value for >resolve
  354.     >resolve
  355.     " dup 2* -> rX" evaluate
  356.     minindex 2* postpone literal " --> rX" evaluate
  357.                                     \ Compiles nothing if minindex is zero
  358.     maxindex minindex - 2* postpone literal
  359.     " rX u< nif" evaluate
  360.  
  361.     drop  restore: fcstk2  restore: cstk2
  362.                                     \ drop cstk state - dflt stub already fixed
  363.     CDP -> svCDP
  364.     dflt_CDP -> CDP 120 >resolve    \ branch is actually back, but that's OK
  365.     svCDP -> CDP
  366.  
  367.     tbl_start  code_addr_in_curr_def
  368.     " -> rY rX rY + w@x -> treg rY +> treg" evaluate        \ treg is r0
  369.  
  370.     $ 7C0903A6  code,                \ mtctr r0
  371.     $ 4E800420 code,                \ bctr
  372.  
  373.  
  374. \ now we'll resolve the endChain - note that the cstk state also needs to be
  375. \  set to what it is at the end of all the stubs - no equalization is needed,
  376. \  since we're just setting it to what it really is already.  We saved this
  377. \  state earlier, in cstk_temp.
  378.  
  379.     save: cstk_temp  save: fcstk_temp
  380.     restore: fcstk  restore: cstk
  381.     update_refcnts
  382.     endChain resolve
  383.     -> minindex  -> maxindex  -> case_type
  384. ;                                        immediate
  385.  
  386.  
  387.  
  388. \ These words are the same in both constructs, so we work out which action
  389. \ to apply by looking at case_type.
  390.  
  391. : ]=>        case_type keyed_case =
  392.             IF        dup  true new_stub
  393.             ELSE    true tbl_new_stub
  394.             THEN  ;                        immediate
  395.             
  396. : ],        case_type keyed_case =
  397.             IF        dup false new_stub
  398.             ELSE    false tbl_new_stub
  399.             THEN  ;                        immediate
  400.  
  401. : RANGE]=>    true new_stub  ;            immediate
  402. : RANGE],    false new_stub  ;            immediate
  403.  
  404.  
  405. : DEFAULT=>
  406. \ case_dbg? if db $ 101 cdp 2drop then
  407.  
  408.             case_type keyed_case =
  409.             IF        default
  410.             ELSE    tbl_default
  411.             THEN  ;                        immediate
  412.  
  413.  
  414. endload
  415.  
  416. +echo
  417.  
  418. \ Torture tests - something as complicated as that needs
  419. \ a bit of systematic testing...
  420.  
  421.  
  422. : q    db
  423.     select[    3 ]=> 23
  424.           [ 2 ]=> 22
  425.           [ 0 ]=> 20
  426.           [ 8 ]=> 28
  427.     default=> 999
  428.     ]select  ;
  429.  
  430. : qq
  431.     case[ 21 ]=> 210
  432.         [ 22 ]=> 220
  433.         [ 80 ], [ 82 ], [ 84 ], [ 86 ]=> 888
  434.         [ 30 40 range]=> 333
  435.         [ 90 ], [ 92 ], [ 170 ]=> -999
  436.         [ 90 ], [ 92 ], [ 100 150 range], [ 170 ]=> -999
  437.         [ 222 ]=>  2220
  438.       default=> 99
  439.      ]case  ;
  440.  
  441.  
  442. : ?CHK
  443.     2dup <>
  444.     IF    cr .h cr .h
  445.         true abort" check FAILED!!!"        \ error if something doesn't
  446.                                             \  give what we expect
  447.     ELSE
  448.         2drop
  449.     THEN
  450. ;
  451.  
  452.  
  453. +echo
  454. 21 qq  210 ?chk
  455. 22 qq  220 ?chk
  456. 80 qq  888 ?chk
  457. 84 qq  888 ?chk
  458. 85 qq  99  ?chk  85 ?chk
  459. 35 qq  333 ?chk
  460. 92 qq  -999 ?chk
  461. 120 qq -999 ?chk
  462. 170 qq -999 ?chk
  463. 222 qq 2220 ?chk
  464. 9999 qq 99 ?chk 9999 ?chk
  465.  
  466. 3 q        23    ?chk
  467. 2 q        22    ?chk
  468. 8 q        28    ?chk
  469. 6 q        999    ?chk  6 ?chk
  470. -1 q    999    ?chk  -1 ?chk
  471. 9  q    999    ?chk  9 ?chk
  472.  
  473.  
  474. \ torture tests WORKED!
  475.